package org.suburban.servlet;
import static org.suburban.resource.Emails.ADMIN_EMAIL;
import static org.suburban.resource.JIDs.normalise;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.xmpp.JID;
import com.google.appengine.api.xmpp.Message;
import com.google.appengine.api.xmpp.MessageBuilder;
import com.google.appengine.api.xmpp.SendResponse;
import com.google.appengine.api.xmpp.XMPPService;
import com.google.appengine.api.xmpp.XMPPServiceFactory;

/**
 * Base servlet class
 * @author Alexey Palamarchuk (slonnik@gmail.com)
 *  
 *  HttpServlet
 *   |----------> XMPPServlet
 *   				|---------->AdminServlet
 *   				|				|---------->AdminWelcomeServlet
 *    				|				|
 *    				|				|---------->AdminHelpServlet
 *    				|
 *    				|
 *    				|---------->ClientServlet
 *    				|				|---------->ClientWelcomeServlet
 *    				|				|
 *					|				|---------->ClientInvitationServlet
 *					|				|
 *					|				|---------->ClientHelpServlet
 *					|				|
 *					|				|---------->PresenceServlet
 *					|				|	
 *					|				|---------->ScheduleServlet
 *					|										|
 *					|										|----------------->FullDayScheduleServlet
 *					|										|
 *					|										|----------------->UpToTimeScheduleServlet	
 *					|			
 *					|
 *					|
 *					|---------->DirectionsServlet
 *					|
 *					|---------->StationsServlet
 *					|
 *					|---------->StaticDataServlet
 *					|
 *					|---------->XMPPSubscriberServlet
 *					|
 *					|---------->XMPPPresenceServlet
 */
@SuppressWarnings("serial")
public class XMPPServlet extends HttpServlet{

	/** logger*/
	protected static final Logger logger = Logger.getLogger(XMPPServlet.class.getName());
	/** reference to XMPP service*/
	protected XMPPService xmpp;
	/** reference to session*/
	Session session;	
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void init() throws ServletException {
		super.init();
		xmpp = XMPPServiceFactory.getXMPPService();
		session = Session.getDefaultInstance(new Properties(), null);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		
	}
	
	/**
	 * send message
	 * @param message	- message text
	 * @param from		- "from" JID
	 * @param to		- "to" JID
	 * @return true, if message was sent successfully otherwise false		
	 */
	protected boolean sendMessage(String message, JID from, JID to)
	{
		Message xmppMessage = new MessageBuilder()
									.withBody(message)
									.withFromJid(from)
									.withRecipientJids(to)
									.build();
		
		SendResponse response = xmpp.sendMessage(xmppMessage);
		
		if(response.getStatusMap().get(to) == SendResponse.Status.SUCCESS)
		{
			/** trace our success*/
			if(logger.isLoggable(Level.FINE))
			{
				logger.log(Level.FINE, "XMPP sending message: Succeeded to send message text={0} to={1} from={2}",
						new Object[]{message, to, from});
			}
		}
		else
		{
			/** Ooops, we failed to send message*/
			logger.log(Level.WARNING, "XMPP sending message: Filed to send message text={0} to={1} from={2}",
					new Object[]{message, to, from});
			return false;
		}
		return true;
	}
	
	/**
	 * send XMPP message with nick name
	 * @param message	- message text
	 * @param nickname	- nickname 
	 * @param from		- "from" JID
	 * @param to		- "to"	JID
	 * @return true, if message was sent successfully otherwise false
	 */
	protected boolean sendMessageWithNickName(String message, String nickname, JID from, JID to)
	{
		String xmppText = String.format(
				"<?xml version=\"1.0\" encoding=\"UTF-8\"?><message from=\"%1$s\" to=\"%2$s\" type=\"chat\">" + 
					"<body>%3$s</body>" + 
					"<nick xmlns=\"http://jabber.org/protocol/nick\">%4$s</nick>" +
				"</message>", from.getId(), to.getId(), message, nickname);
		Message xmppMessage = new MessageBuilder()
								.asXml(true)
								.withFromJid(from)
								.withRecipientJids(to)
								.withBody(xmppText)
								.build();

		SendResponse response = xmpp.sendMessage(xmppMessage);
		
		if(response.getStatusMap().get(to) == SendResponse.Status.SUCCESS)
		{
			/** trace our success*/
			if(logger.isLoggable(Level.FINE))
			{
				logger.log(Level.FINE, "XMPP sending message: Succeeded to send message text={0} to={1} from={2}",
				new Object[]{xmppText, to, from});
			}
		}
		else
		{
			/** Ooops, we failed to send message*/
			logger.log(Level.WARNING, "XMPP sending message: Filed to send message text={0} to={1} from={2}",
					new Object[]{xmppText, to, from});
			return false;
		}
		return true;
	}
	
	/**
	 * send email message
	 * @param subject	- message subject
	 * @param message	- message text
	 * @param from		- "from" JID
	 * @param to		- "to" JID
	 * @return true, if message was sent successfully otherwise false		
	 */
	protected boolean sendEmailMessage(String subject, String message, JID from, JID to)
	{
		try
		{
			javax.mail.Message msg = new MimeMessage(session);
	        msg.setFrom(new InternetAddress(ADMIN_EMAIL));
	        msg.addRecipient(javax.mail.Message.RecipientType.TO,
	                         new InternetAddress(normalise(to).getId()));
	        msg.setSubject(MimeUtility.encodeText(subject, "UTF-16", "B"));
	        msg.setContent(message, "text/html");
	        //msg.setText(message);
	        Transport.send(msg);
	        /** trace our success*/
			if(logger.isLoggable(Level.FINE))
			{
				logger.log(Level.FINE, "Sending email: Succeeded to send message text={0} to={1} from={2}",
						new Object[]{message, to, from});
			}
		}
		catch(Exception ex)
		{
			logger.warning(ex.getMessage());
			return false;
		}
		return true;
	}
	
	/**
	 * Fetch url data
	 * @param request		- string URL representation
	 * @param encoding	- data encoding
	 * @return			- fetched data, otherwise exception
	 */
	protected String fetchURL(String request, String encoding) throws IOException
	{
		URL url = new URL(request);
		
		/** let cache response first*/
		BufferedReader reader = new BufferedReader(new NormaliseReader(url.openStream(), encoding));
		StringBuilder buffer  = new StringBuilder();
		String line;
		while ((line = reader.readLine()) != null) {
            buffer.append(line);
        }
        reader.close();
        return buffer.toString();
	}
}
